package spea.salb1;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;

import salb1.Salb1GeneticOperations;
import salb1.Salb1Genotype;
import salb1.TimeOfOperations;
import spea.*;
import common.GeneticHelper;
import common.GeneticOperations;


public class Salb1Runner {
    public static final int PN = 100; // population size
	public static final int AN = 100; // archive size;
	private final int T = 2000000; // maximum member of generation --- bylo 20000
	private int t = 0;
	private IndividualSet<Salb1Genotype> population;
	private IndividualSet<Salb1Genotype> archive;
	private IndividualSet<Salb1Genotype> newArchive;
	private IndividualSet<Salb1Genotype> matingPool;
	//private GeneticOperations<Salb1Genotype> go;


	//20ms
	private final double timeLimit = 30 * 1000; 
	public static double ref_f0 = 15.0;
	public static double ref_f1 = 15.0;
	private long begMili;
	private long endMili;



	public Salb1Runner(GeneticOperations<Salb1Genotype> aGo) {
		//this.go = aGo;
		population = new IndividualSet<Salb1Genotype>(PN, aGo);
		archive = new IndividualSet<Salb1Genotype>(AN, aGo);
	}


	public static void runExperiment(String input, String output, String hvfile) {	
		TimeOfOperations top = null;
		try {
			top = new TimeOfOperations(input);
		}
		catch (Exception e) { e.printStackTrace(); }

		Salb1GeneticOperations go = new Salb1GeneticOperations(top);
		Salb1Runner salb1Runner = new Salb1Runner(go);

		salb1Runner.begMili = System.currentTimeMillis();


		// 1. Generate an initial population and create the empty archive
		salb1Runner.population.generateRandomIndividuals();
		salb1Runner.t = 0;

		//do zapisywania HV
		BufferedWriter HVout = null;
		try {
			HVout = new BufferedWriter(new FileWriter(hvfile));


			while (true) {
				// 2. Calculate fitness values of individuals in t - population and
				// t - archive
				salb1Runner.population.calculateFitness(salb1Runner.archive);


				/*Iterator<Creature> iter;
			  for (iter = salb1Runner.population.iterator(); iter.hasNext(); )
			  {
			      Creature creature = iter.next();
			      System.out.println("f1: " + creature.getf1() + " f2: " + 
			       creature.getf2() + " strenght: " + creature.getStrength() + " row fitnes: " 
			       + creature.getRowFitness() + " density: " +
			         creature.getDensity() + " fitness: " + creature.getFitness() +
			         " dist: " + creature.getDistance()); 
			  }
			  System.out.println(); System.out.println();*/


				// 3. environmental selection
				// Copy all nondominated individuals in t - population and t - archive to t + 1 archive
				salb1Runner.newArchive = salb1Runner.population.copyNdIndividuals(salb1Runner.archive);

				//HVR
				long time = System.currentTimeMillis() - salb1Runner.begMili;
				if((salb1Runner.t % 20) == 0)
				{
					double HV = GeneticHelper.calculateHiperValume(salb1Runner.newArchive.getIndividuals(), Salb1Runner.ref_f0, Salb1Runner.ref_f1);
					System.out.println("time " + time + " step "+ salb1Runner.t + " HV = " + HV);

					try {
						HVout.write(String.valueOf(time));
						//HVout.write(String.valueOf(salb1Runner.t));
						HVout.write(' ');
						HVout.write(String.valueOf(HV));					
						HVout.newLine();
					} catch (IOException e) {
						System.out.println("IOException " + e.getMessage());
					}
				}

				// 4. Set output and termination
				if ((time >= salb1Runner.timeLimit) | (salb1Runner.t >= salb1Runner.T)) {
					try {
						try {
							BufferedWriter out = new BufferedWriter(new FileWriter(
									output));
							for (int i = 0; i < salb1Runner.newArchive.getIndividuals().size(); i++) {
								Individual<Salb1Genotype> creatureTmp = salb1Runner.newArchive.getIndividuals().get(i);
								out.write(String.valueOf(creatureTmp.getFitness(0)));
								out.write(' ');
								out.write(String.valueOf(creatureTmp.getFitness(1)));					
								out.newLine();
							}
							out.close();

						} catch (FileNotFoundException e) {
							System.out.println("FileNotFoundException " + e);
						}
					} catch (IOException e) {
						System.out.println("IOException " + e);
					}

					if (salb1Runner.t == salb1Runner.T) {
						System.out.println("Wykonano wszystkie kroki");
					}

					salb1Runner.endMili = System.currentTimeMillis();
					System.out.println("Czas trwania = " + (salb1Runner.endMili - salb1Runner.begMili));
					System.out.println("Liczba krokow algorytmu = " + salb1Runner.t);
					System.out.println("Ilość osobników w populacji = " + PN);
					System.out.println("Ilość osobników w archiwum = " + AN);
					System.out.println("ref_f0 = " + ref_f0);
					System.out.println("ref_f1 = " + ref_f1);

					HVout.close();
					return;
				}

				// 5. mating selection
				salb1Runner.matingPool = salb1Runner.newArchive.matingSelection();

				// 6. variation: recombination and mutation
				salb1Runner.matingPool.recombination();
				salb1Runner.matingPool.mutation();
				salb1Runner.population = salb1Runner.matingPool;
				salb1Runner.archive = salb1Runner.newArchive;
				salb1Runner.t++;

				//System.out.println("Iteracja " + salb1Runner.t);
			}
		} catch (IOException e1) {
			System.out.println("IOException " + e1.getMessage());
		}
	}


	public static void main(String args[]) {
		Salb1Runner.runExperiment("inputs/input_30_100_30.txt", "output/output_30_100_30_spea.txt", "output/output_30_100_30_spea_hv.txt");
	}
}
